package com.citic.topview.system.security;

import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

import com.citic.topview.common.bean.Query;
import com.citic.topview.common.security.Principal;
import com.citic.topview.common.system.entity.User;
import com.citic.topview.common.system.vo.MenuVO;
import com.citic.topview.common.util.EncodesUtil;
import com.citic.topview.system.security.manager.RedisCache;
import com.citic.topview.system.security.manager.RedisCacheManager;
import com.citic.topview.system.service.MenuService;
import com.citic.topview.system.service.SystemService;
import com.citic.topview.system.service.UserRoleService;
import com.citic.topview.system.service.UserService;
import com.citic.topview.system.util.ShiroUtils;

public class UserRealm extends AuthorizingRealm {

	@Autowired
    private UserService userService;
	
	@Autowired
	private UserRoleService userRoleService;
	
	@Autowired
	private MenuService menuService;
	
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
		if (authenticationToken instanceof UsernamePasswordToken) {
			UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
	        String username = token.getUsername();
	        
/*	        Session session = ShiroUtils.getSession();
	        String code = (String)session.getAttribute(ValidateCode.VALIDATE_CODE);
			if (token.getCaptcha() == null || !token.getCaptcha().toUpperCase().equals(code)){
				throw new AuthenticationException("msg:验证码错误, 请重试.");
			}*/
	        
	        Map<String, Object> map = new LinkedHashMap<String, Object>();
	        map.put("loginName", username);
	        User user = userService.getByUser(new Query(map));
	        if (user == null) {
	            throw new UnknownAccountException("msg:用户名或密码错误！");
	        }
	        if ("1".equals(user.getStatus())) {
	            throw new LockedAccountException("msg:账号已被锁定,请联系管理员！");
	        }
	        
			user.setLoginDate(new Date());
			userService.update(user);
	        
	        byte[] salt = EncodesUtil.decodeHex(user.getPassword().substring(0, 16));      
	        return new SimpleAuthenticationInfo(new Principal(user, token.isMobileLogin()), user.getPassword().substring(16), ByteSource.Util.bytes(salt), getName());
		
		} else {
			return null;
		}
	}

	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		SimpleAuthorizationInfo authorizationInfo =  new SimpleAuthorizationInfo();
		//获取用户角色ids
		User user = ShiroUtils.getUser();
		List<Long> ids = userRoleService.listRoleId(user.getId());
		
		if(!CollectionUtils.isEmpty(ids)) {
	        //获取用户权限
	        List<MenuVO> menus = menuService.listByRoleIds(ids); 
	        //添加权限
	        for (MenuVO menuVO : menus) {
	        	if(StringUtils.isNotBlank(menuVO.getPermission())) {
					for (String permission : StringUtils.split(menuVO.getPermission(),",")){
						authorizationInfo.addStringPermission(permission);
					}
	        	}
	        }
		}

        return authorizationInfo;
	}
	
	@PostConstruct
	public void initCredentialsMatcher() {
		HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(SystemService.HASH_ALGORITHM);
		matcher.setHashIterations(SystemService.HASH_INTERATIONS);
		setCredentialsMatcher(matcher);
	}
	
	/**
	 * 当修改权限时，可以调用该方法，删除所有权限缓存
	 */
	public void clearAuthz(){
        //this.clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
		RedisCacheManager cacheManager = (RedisCacheManager)getCacheManager();
		cacheManager.deleteAuthorization(RedisCache.REDIS_SHIRO_CACHE + UserRealm.class.getName() + "*"); //这个*一定要加，否则无法模糊查询
    }
}
